/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2022-2022.  All rights reserved.2023.
 */

package service

import (
	"errors"
	"fmt"
	"prim-server/common"
	"prim-server/logger"
	"prim-server/model"
	billService "prim-server/service/bill"
	orderService "prim-server/service/order"
	userService "prim-server/service/user"
	"prim-server/util"
	"sort"
	"sync"
	"time"

	bssModel "github.com/huaweicloud/huaweicloud-sdk-go-v3/services/bss/v2/model"
	"github.com/spf13/cast"
)

const (
	defaultLimit  = int32(1000)
	defaultOffset = int32(0)

	billDateTimeFormat  = "2006-01-02"
	billMonthTimeFormat = "2006-01"
)

// 按照交易时间正序
type billTimeSort []bssModel.MonthlyBillRecord

func (bill billTimeSort) Len() int           { return len(bill) }
func (bill billTimeSort) Swap(i, j int)      { bill[i], bill[j] = bill[j], bill[i] }
func (bill billTimeSort) Less(i, j int) bool { return *bill[i].TradeTime < *bill[j].TradeTime }

type resourceTimeSort []bssModel.ResFeeRecordV2

func (resourceFee resourceTimeSort) Len() int { return len(resourceFee) }
func (resourceFee resourceTimeSort) Swap(i, j int) {
	resourceFee[i], resourceFee[j] = resourceFee[j], resourceFee[i]
}
func (resourceFee resourceTimeSort) Less(i, j int) bool {
	return *resourceFee[i].TradeTime < *resourceFee[j].TradeTime
}

// 按照交易时间正序
type billSort []model.Bill

func (bill billSort) Len() int           { return len(bill) }
func (bill billSort) Swap(i, j int)      { bill[i], bill[j] = bill[j], bill[i] }
func (bill billSort) Less(i, j int) bool { return bill[i].TradeTime < bill[j].TradeTime }

// 获取当前东八区时区时间代表的账期和日期
func GetGMT8BillCycleDateNow() (nowBillCycle, nowBillDate string, err error) {
	updateTime, err := util.GetGMT8TimeNow()
	if err != nil {
		logger.Error("get GMT-8 time error: %v, cycle: %s, date: %s", err.Error(), nowBillCycle, nowBillDate)
		return "", "", err
	}
	updateBillCycle := fmt.Sprintf("%4d-%02d", updateTime.Year(), updateTime.Month())
	updateBillDate := fmt.Sprintf("%4d-%02d-%02d", updateTime.Year(), updateTime.Month(), updateTime.Day())
	return updateBillCycle, updateBillDate, nil
}
func GetBillCycleForDataTableName(billCycleTime time.Time) string {
	return fmt.Sprintf("%4d_%02d", billCycleTime.Year(), billCycleTime.Month())
}

// 从云上账单生成系统账单
func CreateAndSaveCloudBillRecord(userId string,
	cloudBills *bssModel.ListCustomerBillsFeeRecordsResponse) error {
	if len(userId) == 0 || cloudBills == nil {
		return nil
	}
	if *cloudBills.TotalCount == 0 {
		return nil
	}
	currency := ""
	if cloudBills.Currency != nil {
		currency = *cloudBills.Currency
	}
	//分账期获取
	billData := buildCombinedCloudBillRecordForSaveCloudBill(userId, currency, cloudBills)
	if billData == nil {
		return nil
	}
	for _, saveBill := range billData {
		err := billService.CreateAndSaveBillWithCloudBill(&saveBill)
		if err != nil {
			logger.Error("save cloud bill error: %v, userId: %s, cycle: %s", err.Error(), userId, saveBill.BillCycle)
			return err
		}
	}
	//更新拉取时间
	return nil
}
func buildCombinedCloudBillRecordForSaveCloudBill(userId, currency string,
	cloudBills *bssModel.ListCustomerBillsFeeRecordsResponse) []billService.CombinedCloudBillRecord {
	if cloudBills == nil {
		return nil
	}
	//按照交易时间进行账期划分
	//返回数据按照交易时间正序排序
	sort.Sort(billTimeSort(*cloudBills.Records))
	billCount := len(*cloudBills.Records)
	var wg sync.WaitGroup
	orderId := make([]string, billCount)
	cloudResourceId := make([]string, billCount)
	onePayOrder := []*model.OnePayOrder{}
	wg.Add(billCount)
	for index, cloudBill := range *cloudBills.Records {
		go getOrderIdWithCloudBill(&wg, userId, &currency, &onePayOrder, &orderId, &cloudResourceId, index, &cloudBill)
	}
	wg.Wait()
	billData := []billService.CombinedCloudBillRecord{}
	billDataMap := make(map[string]int)
	for index, bill := range *cloudBills.Records {
		billCycleTime, err := util.GetTimeFromUTCStr(*bill.TradeTime)
		if err != nil {
			logger.Error("get bill time error: %v, cycle:%s, tradeId: %s, date: %s", err.Error(), *bill.BillCycle, *bill.TradeId, *bill.TradeTime)
		}
		billCycle := GetBillCycleForDataTableName(billCycleTime)
		if _, ok := billDataMap[billCycle]; !ok {
			combinedRecord := billService.CombinedCloudBillRecord{
				UserId:    userId,
				Currency:  currency,
				BillCycle: billCycle,
			}
			billDataMap[billCycle] = len(billData)
			billData = append(billData, combinedRecord)
		}
		billDataIndex := billDataMap[billCycle]
		billData[billDataIndex].CloudBillRecord = append(billData[billDataIndex].CloudBillRecord, bill)
		billData[billDataIndex].OrderId = append(billData[billDataIndex].OrderId, orderId[index])
		if billService.IsChargeModeOfOnDemand(cast.ToString(*bill.ChargingMode)) {
			billData[billDataIndex].CloudResourceId = append(billData[billDataIndex].CloudResourceId, cloudResourceId[index])
		}
	}
	return billData
}

// 从云上资源消费记录生成系统账单
func CreateAndSaveCloudResourceRecord(userId string,
	cloudResourceFees *bssModel.ListCustomerselfResourceRecordsResponse) error {
	if len(userId) == 0 || cloudResourceFees == nil {
		return nil
	}
	if *cloudResourceFees.TotalCount == 0 {
		return nil
	}
	currency := ""
	if cloudResourceFees.Currency != nil {
		currency = *cloudResourceFees.Currency
	}
	//按照交易时间进行账期划分
	//返回数据按照交易时间正序排序
	//账单订单关联不在账单拉取的时候完成--账单直接写入数据库
	//由自动扣费服务来进行账单的关联
	sort.Sort(resourceTimeSort(*cloudResourceFees.FeeRecords))
	//go协程获取orderId

	//分账期获取
	//得到所有账单的orderId后写入数据库
	billData := []billService.CombinedCloudResourceFeeRecord{}
	billDataMap := make(map[string]int)
	for _, bill := range *cloudResourceFees.FeeRecords {
		billCycleTime, err := util.GetTimeFromUTCStr(*bill.TradeTime)
		if err != nil {
			logger.Error("get bill time error: %v, date:%s, tradeId: %s, tradeTime: %s", err.Error(), *bill.BillDate, *bill.TradeId, *bill.TradeTime)
		}
		billCycle := GetBillCycleForDataTableName(billCycleTime)
		if _, ok := billDataMap[billCycle]; !ok {
			combinedRecord := billService.CombinedCloudResourceFeeRecord{
				UserId:    userId,
				Currency:  currency,
				BillCycle: billCycle,
			}
			billDataMap[billCycle] = len(billData)
			billData = append(billData, combinedRecord)
		}
		billDataIndex := billDataMap[billCycle]
		billData[billDataIndex].CloudResource = append(billData[billDataIndex].CloudResource, bill)
		billData[billDataIndex].OrderId = append(billData[billDataIndex].OrderId, util.EmptyString)
	}
	for _, saveBill := range billData {
		err := billService.CreateAndSaveBillWithCloudRecordFeeRecord(&saveBill)
		if err != nil {
			logger.Error("save cloud resource record error: %v, date:%s, userId: %s", err.Error(), *&saveBill.BillCycle, *&saveBill.UserId)
			return err
		}
	}
	//更新拉取时间
	return nil
}

// 获取资源消费记录
func getResourceDetailWithCloudId(cloudUserId, billCycle, tradeId string) (cloudResourceId, productSpecDesc, cloudResourceName string, err error) {
	resourceRecord, err := billService.PullCloudResourceConsumeRecordWithCloudTradeId(cloudUserId, billCycle, tradeId)
	cloudResourceId = ""
	productSpecDesc = ""
	cloudResourceName = ""
	if err != nil {
		return cloudResourceId, productSpecDesc, cloudResourceName, err
	}
	if resourceRecord == nil {
		return cloudResourceId, productSpecDesc, cloudResourceName, nil
	}
	if *resourceRecord.TotalCount == 0 {
		return cloudResourceId, productSpecDesc, cloudResourceName, nil
	}
	for _, record := range *resourceRecord.FeeRecords {
		if record.ResourceId != nil {
			cloudResourceId = *record.ResourceId
			if record.ProductSpecDesc != nil {
				productSpecDesc = *record.ProductSpecDesc
			}
			if record.RegionName != nil {
				cloudResourceName = *record.RegionName
			}
			break
		}
	}
	return cloudResourceId, productSpecDesc, cloudResourceName, nil
}

// 根据云上交易号得到订单号
// 如果不存在则补充创建订单
func getOrderIdWithCloudBill(wg *sync.WaitGroup, userId string, currency *string, onePayOrderData *[]*model.OnePayOrder,
	orderIds, cloudResourceIds *[]string, index int, cloudBill *bssModel.MonthlyBillRecord) {
	defer wg.Done()
	if cloudBill == nil || orderIds == nil {
		return
	}
	if index > len(*orderIds) {
		return
	}
	chargeMode := cast.ToString(*cloudBill.ChargingMode)
	if billService.IsChargeModeOfOnePay(chargeMode) {
		//包周期订单号对应--tradeID等于云上订单号
		onePayOrder, err := orderService.GetOnePayOrderWithCloudOrderId(*cloudBill.TradeId)
		if err != nil {
			logger.Error("get one pay order error: %v, tradeId: %s", err.Error(), *cloudBill.TradeId)
		}
		if onePayOrder == nil {
			//如果不存在该账单对应的包周期订单，创建该订单
			newOrderId, order, err := orderService.CreateOnePayOrderWithCloudBill(userId, currency, cloudBill)
			if err != nil {
				logger.Error("create one pay order error: %v, tradeId: %s", err.Error(), *cloudBill.TradeId)
				(*orderIds)[index] = ""
				return
			}
			*onePayOrderData = append(*onePayOrderData, order)
			(*orderIds)[index] = newOrderId
			return
		}
		(*orderIds)[index] = onePayOrder.OrderId
		return
	} else if billService.IsChargeModeOfOnDemand(chargeMode) {
		//按需账单暂时无法对应--接口限流
		return
	} else {
		//其他类型--暂不做处理
		return
	}
}
func getOrderIdWithCloudResourceFeeRecord(wg *sync.WaitGroup, userId string, currency *string,
	onePayOrderData *[]*model.OnePayOrder, onDemandOrderData *[]*model.OnDemandOrder,
	orderIds *[]string, index int, cloudResourceFeeRecord *bssModel.ResFeeRecordV2) {
	defer wg.Done()
	if cloudResourceFeeRecord == nil || orderIds == nil {
		return
	}
	if index >= len(*orderIds) {
		return
	}
	(*orderIds)[index] = ""
	chargeMode := *cloudResourceFeeRecord.ChargeMode
	if billService.IsChargeModeOfOnePay(chargeMode) {
		//包周期订单号对应--tradeID等于云上订单号
		onePayOrder, err := orderService.GetOnePayOrderWithCloudOrderId(*cloudResourceFeeRecord.TradeId)
		if err != nil {
			logger.Error("create one pay order error: %v, tradeId: %s", err.Error(), *cloudResourceFeeRecord.TradeId)

			return
		}
		if onePayOrder == nil {
			//如果不存在该账单对应的包周期订单，创建该订单
			newOrderId, order, err := orderService.CreateOnePayOrderWithCloudResourceFeeRecord(userId, currency, cloudResourceFeeRecord)
			if err != nil {
				logger.Error("create one pay order error: %v, tradeId: %s", err.Error(), *cloudResourceFeeRecord.TradeId)
				return
			}
			(*orderIds)[index] = newOrderId
			*onePayOrderData = append(*onePayOrderData, order)
			return
		}
		(*orderIds)[index] = onePayOrder.OrderId
		return
	} else if billService.IsChargeModeOfOnDemand(chargeMode) {
		//按需订单号对应--云上resourceId----系统按需订单号
		//1.先用tradeId获取云上resourceId
		onDemandOrder, err := orderService.GetOnDemandOrderWithPlatformAndResourceId(orderService.GetPlatformTypeOfCloud(), *cloudResourceFeeRecord.ResourceId)
		if err != nil {
			logger.Error("create one pay order error: %v, tradeId: %s", err.Error(), *cloudResourceFeeRecord.TradeId)
			return
		}
		if onDemandOrder == nil {
			//如果不存在该账单对应的按需订单，创建该按需订单
			newOrderId, order, err := orderService.CreateOnDemandOrderWithCloudResourceRecord(userId, currency, cloudResourceFeeRecord)
			if err != nil {
				logger.Error("create one pay order error: %v, tradeId: %s", err.Error(), *cloudResourceFeeRecord.TradeId)
				return
			}
			(*onDemandOrderData) = append((*onDemandOrderData), order)
			(*orderIds)[index] = newOrderId
			return
		}
		(*orderIds)[index] = onDemandOrder.OrderId
		return
	} else {
		//其他类型--暂不做处理
		return
	}
}

// 拉取云上资源消费记录--一个用户的全部资源消费记录
func PullAndSaveCustomerResourceRecordAll(billReverseOffset int32,
	pullParameter *common.PullResourceRecordParameter) (newReverseOffset *int32, err error) {
	checkOffset := false
	for {
		//首次必须校准offset
		if !checkOffset {
			tmpLimit := int32(1)
			pullParameter.Limit = &tmpLimit
		}
		response, err := billService.PullCloudResourceConsumeRecord(pullParameter)
		if err != nil {
			logger.Error("pull cloud resource fee error: %v, userId: %s, cloudUser: %s, cycle: %s, offset: %v, limit: %v",
				err.Error(), pullParameter.UserId, pullParameter.CloudUserId, pullParameter.BillCycle, pullParameter.Offset, pullParameter.Limit)
			return nil, err
		}
		if *response.TotalCount == 0 {
			break
		}
		if !checkOffset {
			*pullParameter.Limit = defaultLimit
			diff := *response.TotalCount - billReverseOffset - *pullParameter.Limit
			if diff >= 0 {
				*pullParameter.Offset = diff
			} else {
				*pullParameter.Offset = 0
			}
			checkOffset = true
			continue
		}
		if billReverseOffset >= *response.TotalCount {
			//如果记录数目和返回结果集条数相同则终止查询
			//由于倒序，所以即使是offset从0开始也无法保证是最新的数据
			break
		}
		//创建这一批账单-一批1000limit
		err = CreateAndSaveCloudResourceRecord(pullParameter.UserId, response)
		if err != nil {
			logger.Error("pull cloud resource fee error: %v, userId: %s, cloudUser: %s, cycle: %s, offset: %v, limit: %v",
				err.Error(), pullParameter.UserId, pullParameter.CloudUserId, pullParameter.BillCycle, pullParameter.Offset, pullParameter.Limit)
			return nil, err
		}
		billReverseOffset += cast.ToInt32(len(*response.FeeRecords))
		if billReverseOffset >= *response.TotalCount {
			//如果记录数目和返回结果集条数相同则终止查询
			break
		}
		//根据已经记录的账单数目反向计算offset
		diff := *response.TotalCount - billReverseOffset - *pullParameter.Limit
		if diff >= 0 {
			*pullParameter.Offset = diff
		} else {
			*pullParameter.Offset = 0
			*pullParameter.Limit = *response.TotalCount - billReverseOffset
		}
	}
	return &billReverseOffset, nil
}

// 拉取云上流水账单--一个用户的全部流水账单
func PullAndSaveCustomerBillRecordAll(billReverseOffset int32,
	pullParameter *common.PullBillParameter) (newReverseOffset *int32, err error) {
	checkOffset := false
	for {
		//首次必须校准offset
		if !checkOffset {
			tmpLimit := int32(1)
			pullParameter.Limit = &tmpLimit
		}
		response, err := billService.PullCloudCustomerBillRecord(pullParameter)
		if err != nil {
			logger.Error("pull cloud resource fee error: %v, userId: %s, cloudUser: %s, cycle: %s, offset: %v, limit: %v",
				err.Error(), pullParameter.UserId, pullParameter.CloudUserId, pullParameter.BillCycle, pullParameter.Offset, pullParameter.Limit)
			return nil, err
		}
		if *response.TotalCount == 0 {
			break
		}
		if !checkOffset {
			*pullParameter.Limit = defaultLimit
			diff := *response.TotalCount - billReverseOffset - *pullParameter.Limit
			if diff >= 0 {
				*pullParameter.Offset = diff
			} else {
				*pullParameter.Offset = 0
			}
			checkOffset = true
			continue
		}
		if billReverseOffset >= *response.TotalCount {
			//如果记录数目和返回结果集条数相同则终止查询
			//由于倒序，所以即使是offset从0开始也无法保证是最新的数据
			break
		}
		//创建这一批账单-一批1000limit
		err = CreateAndSaveCloudBillRecord(pullParameter.UserId, response)
		if err != nil {
			logger.Error("pull cloud resource fee error: %v, userId: %s, cloudUser: %s, cycle: %s, offset: %v, limit: %v",
				err.Error(), pullParameter.UserId, pullParameter.CloudUserId, pullParameter.BillCycle, pullParameter.Offset, pullParameter.Limit)
			return nil, err
		}
		billReverseOffset += cast.ToInt32(len(*response.Records))
		if billReverseOffset >= *response.TotalCount {
			//如果记录数目和返回结果集条数相同则终止查询
			break
		}
		//根据已经记录的账单数目反向计算offset
		diff := *response.TotalCount - billReverseOffset - *pullParameter.Limit
		if diff >= 0 {
			*pullParameter.Offset = diff
		} else {
			*pullParameter.Offset = 0
			*pullParameter.Limit = *response.TotalCount - billReverseOffset
		}
	}
	return &billReverseOffset, nil
}

// 构造拉取账单参数,includeZeroRecord指是否包含0元记录，默认不包含
func buildPullBillParameterForPullLastestOne(userId, cloudUserId string, chargeMode *string, limit, offset *int32, includeZeroRecord *bool) *common.PullBillParameter {
	pullLimit := defaultLimit
	pullOffset := defaultOffset
	if limit != nil {
		if *limit > 0 {
			pullLimit = *limit
		}
	}
	if offset != nil {
		if *offset > 0 {
			pullOffset = *offset
		}
	}
	needIncludeZeroRecord := false
	if includeZeroRecord != nil {
		needIncludeZeroRecord = *includeZeroRecord
	}
	pullBillParameter := common.PullBillParameter{
		UserId: userId,
		BillAndResourceMixedParameter: common.BillAndResourceMixedParameter{
			CloudUserId:       cloudUserId,
			Offset:            &pullOffset,
			Limit:             &pullLimit,
			IncludeZeroRecord: &needIncludeZeroRecord,
		},
		BillAndResourceCommonParameter: common.BillAndResourceCommonParameter{},
	}
	if chargeMode != nil {
		pullBillParameter.BillAndResourceCommonParameter.ChargeMode = chargeMode
	}
	return &pullBillParameter
}

// 构造拉取资源消费记录参数,includeZeroRecord指是否包含0元记录，默认不包含
func buildPullResourceFeeParameterForPullLastestOne(userId, cloudUserId string, chargeMode *string, limit, offset *int32, includeZeroRecord *bool) *common.PullResourceRecordParameter {
	pullLimit := defaultLimit
	pullOffset := defaultOffset
	if limit != nil {
		if *limit > 0 {
			pullLimit = *limit
		}
	}
	if offset != nil {
		if *offset > 0 {
			pullOffset = *offset
		}
	}
	needIncludeZeroRecord := true
	if includeZeroRecord != nil {
		needIncludeZeroRecord = *includeZeroRecord
	}
	pullBillParameter := common.PullResourceRecordParameter{
		UserId: userId,
		BillAndResourceMixedParameter: common.BillAndResourceMixedParameter{
			CloudUserId:       cloudUserId,
			Offset:            &pullOffset,
			Limit:             &pullLimit,
			IncludeZeroRecord: &needIncludeZeroRecord,
		},
		BillAndResourceCommonParameter: common.BillAndResourceCommonParameter{},
	}
	if chargeMode != nil {
		pullBillParameter.BillAndResourceCommonParameter.ChargeMode = chargeMode
	}
	return &pullBillParameter
}

// 不区分收费模式--拉取资源消费记录
func PullCloudResourceFeeLastestOne(userId string, queryChargeMode string) error {
	//获取云上用户
	cloudUser, err := userService.GetCloudUserOne(userId)
	if err != nil {
		logger.Error("get cloud user error: %v, userId: %s", err.Error(), userId)
		return err
	}
	pullBillParameter := buildPullResourceFeeParameterForPullLastestOne(userId, cloudUser.CloudId, &queryChargeMode, nil, nil, nil)
	//获取当前东八区时间,CBC接口限制
	_, nowDate, err := GetGMT8BillCycleDateNow()
	if err != nil {
		logger.Error(err.Error())
		return err
	}
	// 获取上次更新时间
	billRecord, err := billService.GetBillUpdateRecordOneWithUserId(userId)
	if err != nil {
		logger.Error("get bill error: %v, userId: %s", err.Error(), userId)
		return err
	}
	//1.如果当前账期和上次更新时间的账期相同，直接拉取，reverseOffset公用
	//2.如果不同，则需要从上次的账期开始直到当前账期开始逐渐拉取到当前账期
	//获取不同类型账单的账期和reverseOffset
	reverseOffset := int32(0)
	billBegin := ""
	if billService.IsChargeModeOfOnePay(queryChargeMode) {
		reverseOffset = billRecord.ResourceUpdateOnePayReverseOffset
		billBegin = billRecord.ResourceUpdateOnePayDateBegin
	} else if billService.IsChargeModeOfOnDemand(queryChargeMode) {
		reverseOffset = billRecord.ResourceUpdateOnDemandReverseOffset
		billBegin = billRecord.ResourceUpdateOnDemandDateBegin
	} else {
		err = errors.New("not support chargeMode")
		logger.Error("pull resource fee error: %v, userId: %s, chargeMode: %s", err.Error(), userId, queryChargeMode)
		return err
	}
	billDateBegin, err := time.Parse(billDateTimeFormat, billBegin)
	if err != nil {
		logger.Error("parse time error:%v,userId:%v, billBegin: %s", err, userId, billBegin)
		return err
	}
	billDateEnd, err := time.Parse(billDateTimeFormat, nowDate)
	if err != nil {
		logger.Error("parse time error:%v,userId:%v, billDateEnd: %s", err, userId, billDateEnd)
		return err
	}
	if billDateBegin.Equal(billDateEnd) {
		return nil
	}
	//error has been handle, return directly
	err = affairsOnPullCloudResourceFeeLastestOne(billDateBegin, billDateEnd, userId, queryChargeMode, reverseOffset, pullBillParameter)
	if err != nil {
		return err
	}
	return nil
}
func affairsOnPullCloudResourceFeeLastestOne(billDateBegin, billDateEnd time.Time, userId string, queryChargeMode string,
	reverseOffset int32, pullBillParameter *common.PullResourceRecordParameter) (err error) {
	startTime := billDateBegin
	for billDateBegin.Before(billDateEnd) || billDateBegin.Equal(billDateEnd) {
		pullBillParameter.BillCycle = billDateBegin.Format(billMonthTimeFormat)
		dateBegin := billDateBegin.Format(billDateTimeFormat)
		dateEnd := billDateBegin.Format(billDateTimeFormat)
		pullBillParameter.BillDateBegin = &dateBegin
		pullBillParameter.BillDateEnd = &dateEnd
		if billDateBegin.Equal(billDateEnd) {
			//如果当前时间是最新的一天，则直接返回
			err = billService.UpdateResourceRecordInfo(userId, queryChargeMode, &pullBillParameter.BillCycle, pullBillParameter.BillDateBegin, &reverseOffset)
			if err != nil {
				logger.Error("update resource record error: %v, userId: %s, chargeMode: %s, cycle: %s, begin: %s, offset: %v, limite: %v, reverseOffset: %v",
					err.Error(), userId, queryChargeMode, pullBillParameter.BillCycle, pullBillParameter.BillDateBegin, pullBillParameter.Offset, pullBillParameter.Limit, reverseOffset)
				return err
			}
			break
		}
		//更新reverseOffset
		if !billDateBegin.Equal(startTime) {
			reverseOffset = int32(0)
			err = billService.UpdateResourceRecordInfo(userId, queryChargeMode, &pullBillParameter.BillCycle, pullBillParameter.BillDateBegin, &reverseOffset)
			if err != nil {
				logger.Error("update resource record error: %v, userId: %s, chargeMode: %s, cycle: %s, begin: %s, offset: %v, limite: %v, reverseOffset: %v",
					err.Error(), userId, queryChargeMode, pullBillParameter.BillCycle, pullBillParameter.BillDateBegin, pullBillParameter.Offset, pullBillParameter.Limit, reverseOffset)
				return err
			}
		}
		newReverOffset, err := PullAndSaveCustomerResourceRecordAll(reverseOffset, pullBillParameter)
		if err != nil {
			logger.Error("pull resource record error: %v, userId: %s, chargeMode: %s, cycle: %s, begin: %s, offset: %v, limite: %v, reverseOffset: %v",
				err.Error(), userId, queryChargeMode, pullBillParameter.BillCycle, pullBillParameter.BillDateBegin, pullBillParameter.Offset, pullBillParameter.Limit, reverseOffset)
			return err
		}
		if newReverOffset == nil {
			err = errors.New("newReverOffset is nil")
			return err
		}
		billDateBegin = billDateBegin.AddDate(0, 0, 1) //按天计算
		offset := defaultOffset
		pullBillParameter.Offset = &offset
	}
	return nil
}

// 不区分付费模式--拉取流水账单
func PullCloudBillLastestOne(userId string, queryChargeMode string) error {
	//获取云上用户
	cloudUser, err := userService.GetCloudUserOne(userId)
	if err != nil {
		logger.Error("get cloud user error: %v, userId: %s", err.Error(), userId)
		return err
	}
	pullBillParameter := buildPullBillParameterForPullLastestOne(userId, cloudUser.CloudId, &queryChargeMode, nil, nil, nil)

	//获取当前东八区时间
	_, nowDate, err := GetGMT8BillCycleDateNow()
	if err != nil {
		logger.Error(err.Error())
		return err
	}
	// 获取上次更新时间
	billRecord, err := billService.GetBillUpdateRecordOneWithUserId(userId)
	if err != nil {
		logger.Error("get bill error: %v, userId: %s", err.Error(), userId)
		return err
	}
	//1.如果当前账期和上次更新时间的账期相同，直接拉取，reverseOffset公用
	//2.如果不同，则需要从上次的账期开始直到当前账期开始逐渐拉取到当前账期
	//获取不同类型账单的账期和reverseOffset
	reverseOffset := int32(0)
	billBegin := ""
	if billService.IsChargeModeOfOnePay(queryChargeMode) {
		reverseOffset = billRecord.BillUpdateOnePayReverseOffset
		billBegin = billRecord.BillUpdateOnePayDateBegin
	} else if billService.IsChargeModeOfOnDemand(queryChargeMode) {
		reverseOffset = billRecord.BillUpdateOnDemandReverseOffset
		billBegin = billRecord.BillUpdateOnDemandDateBegin
	} else {
		err = errors.New("not support chargeMode")
		logger.Error("pull bill error: %v, userId: %s, chargeMode: %s", err.Error(), userId, queryChargeMode)
		return err
	}
	billDateBegin, err := time.Parse(billDateTimeFormat, billBegin)
	if err != nil {
		logger.Error("parse time error:%v,userId:%v, billBegin: %s", err, userId, billBegin)
		return err
	}
	billDateEnd, err := time.Parse(billDateTimeFormat, nowDate)
	if err != nil {
		logger.Error("parse time error:%v,userId:%v, billDateEnd: %s", err, userId, billDateEnd)
		return err
	}
	if billDateBegin.Equal(billDateEnd) {
		return nil
	}
	err = affairsOnPullCloudBillLastestOne(billDateBegin, billDateEnd, userId, queryChargeMode, reverseOffset, pullBillParameter)
	if err != nil {
		return err
	}
	return nil
}

func affairsOnPullCloudBillLastestOne(billDateBegin, billDateEnd time.Time, userId string, queryChargeMode string,
	reverseOffset int32, pullBillParameter *common.PullBillParameter) (err error) {
	startTime := billDateBegin
	for billDateBegin.Before(billDateEnd) || billDateBegin.Equal(billDateEnd) {
		pullBillParameter.BillCycle = billDateBegin.Format(billMonthTimeFormat)
		dateBegin := billDateBegin.Format(billDateTimeFormat)
		dateEnd := billDateBegin.Format(billDateTimeFormat)
		pullBillParameter.BillDateBegin = &dateBegin
		pullBillParameter.BillDateEnd = &dateEnd
		if billDateBegin.Equal(billDateEnd) {
			//如果当前时间是最新的一天，则直接返回
			err = billService.UpdateBillRecordInfo(userId, queryChargeMode, &pullBillParameter.BillCycle, pullBillParameter.BillDateBegin, &reverseOffset)
			if err != nil {
				logger.Error("update resource record error: %v, userId: %s, chargeMode: %s, cycle: %s, begin: %s, offset: %v, limite: %v, reverseOffset: %v",
					err.Error(), userId, queryChargeMode, pullBillParameter.BillCycle, pullBillParameter.BillDateBegin, pullBillParameter.Offset, pullBillParameter.Limit, reverseOffset)
				return err
			}
			break
		}
		//更新reverseOffset
		if !billDateBegin.Equal(startTime) {
			reverseOffset = int32(0)
			err = billService.UpdateBillRecordInfo(userId, queryChargeMode, &pullBillParameter.BillCycle, pullBillParameter.BillDateBegin, &reverseOffset)
			if err != nil {
				logger.Error("update resource record error: %v, userId: %s, chargeMode: %s, cycle: %s, begin: %s, offset: %v, limite: %v, reverseOffset: %v",
					err.Error(), userId, queryChargeMode, pullBillParameter.BillCycle, pullBillParameter.BillDateBegin, pullBillParameter.Offset, pullBillParameter.Limit, reverseOffset)
				return err
			}
		}
		newReverOffset, err := PullAndSaveCustomerBillRecordAll(reverseOffset, pullBillParameter)
		if err != nil {
			logger.Error("update resource record error: %v, userId: %s, chargeMode: %s, cycle: %s, begin: %s, offset: %v, limite: %v, reverseOffset: %v",
				err.Error(), userId, queryChargeMode, pullBillParameter.BillCycle, pullBillParameter.BillDateBegin, pullBillParameter.Offset, pullBillParameter.Limit, reverseOffset)
			return err
		}
		if newReverOffset == nil {
			err = errors.New("newReverOffset is nil")
			return err
		}
		billDateBegin = billDateBegin.AddDate(0, 0, 1) //按天计算
		offset := defaultOffset
		pullBillParameter.Offset = &offset
	}
	return nil
}

// 包周期账单
func PullOnePayCloudBillLastestOne(userId string) error {
	chargeMode := billService.GetChargeModeOfOnePay()
	return PullCloudBillLastestOne(userId, chargeMode)
}

func PullOnePayCloudBillLastestAll(userId []string) error {
	for _, user := range userId {
		err := PullOnePayCloudBillLastestOne(user)
		if err != nil {
			logger.Error(err.Error())
			return err
		}
	}
	return nil
}

// 按需账单
func PullOnDemandCloudBillLastestOne(userId string) error {
	chargeMode := billService.GetchargeModeOfOnDemand()
	return PullCloudBillLastestOne(userId, chargeMode)
}

func PullOnDemandCloudBillLastestAll(userId []string) error {
	for _, user := range userId {
		err := PullOnDemandCloudBillLastestOne(user)
		if err != nil {
			logger.Error(err.Error())
			return err
		}
	}
	return nil
}

// 包周期资源消费记录
func PullOnePayCloudResourceFeeLastestOne(userId string) error {
	chargeMode := billService.GetChargeModeOfOnePay()
	return PullCloudResourceFeeLastestOne(userId, chargeMode)
}

func PullOnePayCloudResourceFeeLastestAll(userId []string) error {
	for _, user := range userId {
		err := PullOnePayCloudResourceFeeLastestOne(user)
		if err != nil {
			logger.Error(err.Error())
			return err
		}
	}
	return nil
}

// 按需资源消费记录
func PullOnDemandCloudResourceFeeLastestOne(userId string) error {
	chargeMode := billService.GetchargeModeOfOnDemand()
	return PullCloudResourceFeeLastestOne(userId, chargeMode)
}

func PullOnDemandCloudResourceFeeLastestAll(userId []string) error {
	for _, user := range userId {
		err := PullOnDemandCloudResourceFeeLastestOne(user)
		if err != nil {
			logger.Error(err.Error())
			return err
		}
	}
	return nil
}
